#ifndef STATE_H_
#define STATE_H_

#include <iostream>
#include <stdio.h>
#include <cstdlib>
#include <cmath>
#include <string>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <queue>
#include "Timer.h"
#include "Logger.h"
#include "Square.h"
#include "Location.h"

/*
    constants
*/
const int TDIRECTIONS = 4;
const char CDIRECTIONS[4] = {'N', 'E', 'S', 'W'};
const int DIRECTIONS[4][2] = { {-1, 0}, {0, 1}, {1, 0}, {0, -1} };      //{N, E, S, W}

class PlayerQueueEntry {
public:
    int playerId;
    int numAnts;
public:
    PlayerQueueEntry(const int& id,const int& nAnts): playerId(id),numAnts(nAnts) {}
    bool operator < (const PlayerQueueEntry& other) const{
	return numAnts > other.numAnts; //more ants higher priority
    }
};

typedef std::priority_queue<PlayerQueueEntry> PlayerQueue;

/*
    struct to store current state information
*/
struct State
{
    /*
        Variables
    */
    int rows, cols,
        turn, turns,
        noPlayers;
    double attackradius, spawnradius, viewradius;
    double loadtime, turntime;
    std::vector<double> scores;
    bool gameover;
    std::vector<std::vector<Square> > grid;
    std::vector<Location> ants, enemies, food;
    std::map<Location,int> foodTrackingPathLengths;
    Timer timer;
    std::vector<Location> frontLine;
    //ordered by list of players with highest strength up first
    //useful for target selection. We want to make sure stronger
    //players don't get stronger to prevent exponential growth.
    PlayerQueue playerQ;
    /*
        Functions
    */
    State();
    ~State();

    void setup();
    void reset();

    void makeMove(const Location &loc, int direction);


    //useful for evaluating future states.
    void mockMakeMove(const Location& loc,int direction);
    void unmakeMockMove(const Location &loc,int direction);


    double distance(const Location &loc1, const Location &loc2) const;
    double manhattan_distance(const Location& loc1, const Location &loc2) const;
    Location getLocation(const Location &startLoc, int direction) const;

    void updateVisionInformation();
    void analyzeMap();
    bool isEdgeLocation(const int& row,const int& col);

    //All Pathfinding functions
    //path from loc1 to loc2
    bool findPath(const Location& loc1, const Location& loc2,
		  std::stack<int>& path,int& numNodesExplored
		  ) const;
    //Returns the closest untracked food
    bool findClosestFood(const Location& loc,Location& foodLoc,std::stack<int>& path,int& numNodesExplored) const;
    //Always returns the closest enemy ant tracked or not
    bool findClosestEnemyAnt(const Location& loc,Location& antLoc,std::stack<int>& path,int& numNodesExplored) const;
    //Always returns the closest friendly ant except the one on loc itself.
    bool findClosestFriendlyAnt(const Location& loc,Location& antLoc,std::stack<int>& path,int& numNodesExplored) const;

    //All Query Functions
    //find all ants(friendly/enemy) within a certain radius 
    void findAntsInRadius(Location loc,double radius,std::vector<Location>& antList) const;
    void findFriendlyAntsInRadius(Location loc,double radius,std::vector<Location>& antList) const;

private:
    void extractPath(const Location& startLoc,const std::vector< std::vector<int> >& visited,std::stack<int>& path) const;
};

std::ostream& operator<<(std::ostream &os, const State &state);
std::istream& operator>>(std::istream &is, State &state);

#endif //STATE_H_
